﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Framework;
using SchemaMonitor;
using System.Data;
using System.IO;
using System.Drawing;
using System.Web;

namespace ImageUploader
{
	class Program
	{
		const int IGNORE_MATCHES = Int16.MaxValue / 4;

		static void Main(string[] args)
		{
            //DATABASE
			CDataSrc localPhotos = new CSqlClient("server=.;database=JewBookPhotos;Trusted_Connection=True;");
			CDataSrc localFacebk = new CSqlClient("server=.;database=FacebookRecycleBin;Trusted_Connection=True;");
            var remotePhotos = new CWebSrcBinary("http://recyclebin.mikeconnellministries.com/webservices/FBDatasrc.ashx");
            var remoteFaceBk = new CWebSrcBinary("http://recyclebin.mikeconnellministries.com/datasrc.aspx");

            CConfig.Photos = remotePhotos;
			CDataSrc.Default = remoteFaceBk;


            //EXPORT
            //ExportImages();
            ExportPosts();
            Console.WriteLine("Finished");
            Console.ReadLine();



            ////RECOVER Lost Chapter images

            //var dp = new Dictionary<CChapterPicture, Guid>();
            //foreach (var i in CChapterPicture.Cache)
            //    if (null == i.PhotoHash)
            //        dp.Add(i, i.PicturePhotoMD5);

            //var df = new Dictionary<string, Guid>();
            //foreach (var i in Directory.GetDirectories(@"C:\Dev\facebook-100014244433824\photos"))
            //    foreach (var j in Directory.GetFiles(i))
            //        df.Add(j, CBinary.MD5_(File.ReadAllBytes(j)));

            //int w = 0;
            //int h = 0;
            //int missing = dp.Count;
            //int refound = 0;
            //var u = new CUser(1);
            //foreach (var i in dp)
            //    foreach (var j in df)
            //        if (i.Value == j.Value)
            //        {
            //            //missing++;
            //            var exact = CPhotoHash.Cache.GetById(i.Value);
            //            if (null != exact)
            //                continue;

            //            var rgb = CPhotoHash.Image2Thumb(j.Key, ref w, ref h);
            //            var gz = CBinary.Zip(CProto.Serialise(rgb));
            //            var md5thumb = CBinary.MD5_(gz);

            //            var pp = CPhotoHash.Cache.GetByThumbMD5(md5thumb);
            //            if (pp.Count > 0)
            //            {
            //                refound++;
            //                i.Key.PicturePhotoMD5 = pp[0].PhotoMd5;
            //                i.Key.Save();
            //            }
            //        }
            //foreach (var i in dp)
            //{
            //    var cp = i.Key;
            //    var n = cp.Chapter.Node_(u);
            //    var sp = new SchemaMonitor.json.CSoftPost(n.Root, u);
            //    var ids = sp.PhotoIds;
            //    var ph = CPhoto.Cache.GetByIds(ids);
            //    var expecting = new CPhotoList(ph);
            //    var actual = cp.Chapter.ChapterPictures.Photos;
            //    foreach (var j in ph)
            //        if (actual.Contains(j.PhotoHash))
            //            expecting.Remove(j);
            //    if (expecting.Count == 0)
            //        continue;

            //    foreach (var j in cp.Chapter.ChapterPictures)
            //        if (j.PhotoHash == null && expecting.Count > 0)
            //        {
            //            j.PicturePhotoMD5 = expecting[0].Md5;
            //            j.Save();
            //            expecting.RemoveAt(0);
            //            refound++;
            //        }
            //}

            //Console.WriteLine(CUtilities.NameAndCount("missing", missing));
            //Console.WriteLine(CUtilities.NameAndCount("refound", refound));

            //Console.WriteLine("Done");
            //Console.ReadLine();







            //UPLOADER
            var dict = CPhotoHash.GetThumbs();
			var files = new List<string>( Directory.GetFiles(CConfig.ImagesFolder));
			//files.AddRange(Directory.GetFiles("D:\\_dump_photos\\twitter"));

			var po = new ParallelOptions();
			po.MaxDegreeOfParallelism = 2;


			int count = 0;
            var LAPTOP = CMetaTag.Cache.Laptop;
            Parallel.ForEach(files, po,  path =>
			{
				count++;

				var x = path.ToLower();
				if (!(x.EndsWith(".jpg") || x.EndsWith(".png") || x.EndsWith(".jpeg")))
				{
					Console.WriteLine(Path.GetFileName(x));
					return;
				}

				var filename = Path.GetFileName(path);
				var bin = File.ReadAllBytes(path);
				var md5 = CBinary.MD5_(bin);
                var fi = new FileInfo(path);

                var p = CPhotoHash.Cache.GetById(md5);
				int width = 0;
				int height = 0;
				if (null != p)
				{
                    bool savePending = false;
					if (string.IsNullOrEmpty(p.PhotoFileNames))
					{
						p.PhotoFileNames = filename;
                        savePending = true;
                    }
					if (Guid.Empty == p.PhotoThumbMD5)
					{
						p.PhotoThumb48x48_Int16ProtoGz = CPhotoHash.Image2ThumbGz(path, ref width, ref height);
						p.PhotoThumbMD5 = CBinary.MD5_(p.PhotoThumb48x48_Int16ProtoGz);
                        savePending = true;
                    }
                    if (p.PhotoCreated != fi.LastWriteTime)
                    {
                        p.PhotoCreated = fi.LastWriteTime;
                        savePending = true;
                    }
                    if (savePending)
                        p.Save();


                    if (0 == p.Labels.Count + p.Label_OneToOnes.Count)
                    {
                        var missed = new CLabel_OneToOne();
                        missed.LabelGuid = p.PhotoMd5;
                        missed.LabelTagId = LAPTOP.TagId;
                        missed.LabelTypeId = LAPTOP.TagTypeId;
                        missed.Save();
                    }
					return;
				}

				var rgb = CPhotoHash.Image2Thumb(path, ref width, ref height);
				var gz = CBinary.Zip(CProto.Serialise(rgb));
				var md5thumb = CBinary.MD5_(gz);

				var pp = CPhotoHash.Cache.GetByThumbMD5(md5thumb);
				if (pp.Count > 0)
				{
					p = pp[0];
					if (null != p.PhotoFileNames)
						if (p.PhotoFileNames == filename || p.PhotoFileNames.Contains(filename))
							return;
					p.PhotoFileNames = string.IsNullOrEmpty(p.PhotoFileNames) ? filename : p.PhotoFileNames + "," + Path.GetFileName(path);
					p.Save();
					return;
				}

                //Check for near matches
                if (CPhotoHash.HasMatch(dict, rgb, IGNORE_MATCHES))
                {
                    Console.WriteLine("\t" + filename);
                    return;
                }

				p = new CPhotoHash();
				p.PhotoFileNames = filename;
				p.PhotoSize = bin.Length;
				p.PhotoMd5 = md5;
				p.PhotoHeight = height;
				p.PhotoWidth = width;
				p.PhotoThumbMD5 = md5thumb;
				p.PhotoThumb48x48_Int16ProtoGz = gz;
				p.PhotoCreated = fi.LastWriteTime;
				p.PhotoBlob = bin;
				try
				{
					p.Save();
				}
				catch
				{
					if (null != CPhotoHash.Cache.GetById(p.PhotoMd5))
						return;
					System.Threading.Thread.Sleep(30000);
					try
					{
						p.Save();
					}
					catch
					{
						return;
					}
				}

				lock (dict)
				{
					dict.Add(p.PhotoMd5, rgb);
					if (new Random().Next(1, 50) == 5)
						CPhotoHash.SetThumbs(dict);
				}

				var lbl = new CLabel_OneToOne();
				lbl.LabelGuid = md5;
				lbl.LabelTagId = LAPTOP.TagId;
                lbl.LabelTypeId = LAPTOP.TagTypeId;
				try
				{
					lbl.Save();
				}
				catch
				{
					lbl.Save();
				}



				int num = count;// (1 + files.IndexOf(path));
				var s = string.Concat(num, " of ", files.Count, " (", (100.0 * num / files.Count).ToString("n0"), "%)");
				Console.WriteLine(s + "\t" + p.Size_ + "\t" + p.PhotoFileNames);
			});

			CPhotoHash.SetThumbs(dict);


			Console.WriteLine("Finished");
			Console.ReadLine();

		}


		#region Images
		static string ImageFileName(CPhotoHash i, bool old = false)
		{
			var name = string.Concat(i.PhotoCreated.Ticks, "_", CBinary.BytesToHex(i.PhotoMd5.ToByteArray()).Substring(0, 10).ToLower());
			if (old)
				name = (i.PhotoCreated.Ticks / 1000).ToString();
			var list = CUtilities.SplitOn(i.PhotoFileNames ?? string.Empty, "\r\n");
			if (!string.IsNullOrEmpty(i.PhotoFileNames))
				name = name += Path.GetExtension(list[0]);
			else
				name += ".jpg";
			return name.ToLower();
		}
		static string FolderName(CPhotoHash ph)
		{
			return ph.Labels.Count == 0 ? "_untagged" : FolderName(ph.Labels[0].MetaTag) + "/";
		}
		static string FolderName(CMetaTag tag)
		{
			return tag.TagName.Replace("/", "_").Replace("\\", "");
		}

		static void ExportImages( bool deleted = false, bool xrated = true, string path = "c:\\_dump_photos\\export\\images\\")
		{
			Console.WriteLine("Exporting Images: " + path);
			if (!xrated)
				Console.WriteLine("* except x-rated");
			if (!deleted)
				Console.WriteLine("* unless deleted");

			var del = CMetaTag.Cache.Delete;
			var xr = CMetaTag.Cache.XRated;


			var dirs = new List<string>();
            foreach(var t in CTagType.Cache.FB_Album.MetaTags)
            {
                var toExport = t.Labels.PhotoHashs;
                if (!deleted)
                    toExport = toExport.Except(toExport.Delete);
                if (!xrated)
                    toExport = toExport.Except(toExport.XRated);

                var tt = FolderName(t);
                var s = path + tt + "\\";

                if (!Directory.Exists(s))
                    Directory.CreateDirectory(s);

                if (toExport.Count == 0)
                {
                    Directory.Delete(s);
                    return;
                }
                dirs.Add(s);

                var names = new List<string>();
                foreach (var i in toExport)
                {
                    var imgPath = s + ImageFileName(i);
                    var old = s + ImageFileName(i, true);

                    if (!deleted && del.PhotoHashs.GetById(i.PhotoMd5) != null)
                    {
                        if (File.Exists(imgPath))
                            File.Delete(imgPath);
                    }
                    else if (!xrated && xr.PhotoHashs.GetById(i.PhotoMd5) != null)
                    {
                        if (File.Exists(imgPath))
                            File.Delete(imgPath);
                    }
                    else
                    {
                        if (!File.Exists(imgPath))
                        {
                            if (File.Exists(old))
                                File.Move(old, imgPath);
                            else
                                File.WriteAllBytes(imgPath, i.GetBlob());
                        }
                        names.Add(Path.GetFileName(imgPath));
                    }
                }
                foreach (var i in Directory.GetFiles(s))
                {
                    var name = Path.GetFileName(i);
                    if (!names.Contains(name))
                        File.Delete(i);
                }
            }

			foreach (var i in Directory.GetDirectories(path))
				if (!dirs.Contains(i + "\\") && !i.Contains("_untagged"))
					Directory.Delete(i, true);

			var other = path + "_untagged\\";
			if (!Directory.Exists(other))
				Directory.CreateDirectory(other);
			foreach (var i in CPhotoHash.Cache)
				if (i.Labels.Count == 0 && i.ChapterPictures.Count > 0)
				{
					var name = ImageFileName(i);
					var imgPath = other + name;
					if (!File.Exists(imgPath))
						File.WriteAllBytes(imgPath, i.GetBlob());
				}

			Console.WriteLine("Finished");
		}
		#endregion



		#region Content
		static void ExportPosts(string path = "c:\\_dump_photos\\export\\posts\\")
		{
			var u = new CUser(1);

			var templates = @"C:\TFS06\connectionmanager\ConnectionMonitor\Website\app_data\";
			var s = new CTemplate("section2.htm", templates);
			var c = new CTemplate("chapter2.htm", templates);
			var cl = new CTemplate("ChapterLink.htm", templates);

			if (!Directory.Exists(path))
				Directory.CreateDirectory(path);
			foreach (var b in CBook.Cache)
				if (b.BookName == "Master")
					foreach (var i in b.Sections)
					{
						var filePath = path + FileName(i) + ".html";

						var p1 = (1 + b.Sections.IndexOf(i));
						s.Reset();
						s.Replace("Links", Links(b.Sections, i));
						s.Replace("SectionId", i.SectionId.ToString());
						s.Replace("SectionName", HttpUtility.HtmlEncode(i.SectionName));
						s.Replace("Prefix", string.Concat(p1, ". "));
						s.Replace("Chapters", ToHtml_Content(i, c, u));
						s.Replace("ChapterLinks", ToHtml_Links(i, cl));
						File.WriteAllText(filePath, s.Template);

						//var dir = path + i.SectionName + "\\";
						//if (!Directory.Exists(dir))
						//	Directory.CreateDirectory(dir);
						//foreach (var j in i.Chapters)
						//{
						//	filePath = dir + FileName(j.ChapterName);
						//	File.WriteAllText(filePath, ToHtml_Content(i, j, c, u));
						//}
					}
		}

		private static string Links(CSectionList ss, CSection s)
		{
			var sb = new StringBuilder();
			foreach (var i in ss)
				sb.Append(Link(i, i.SectionId == s.SectionId, ss.IndexOf(i) + 1)).AppendLine("<br/>");
			return sb.ToString();
		}
		private static string Link(CSection s, bool selected, int num)
		{
			if (selected)
				return string.Concat("<span style='color:black'>", num, ". ", HttpUtility.HtmlEncode(s.SectionName), "</span>");
			return string.Concat("<a href='", FileName(s), ".html'>", num, ". ", HttpUtility.HtmlEncode(s.SectionName), "</a>");
		}
		private static string FileName(CSection s)
		{
			return CUtilities.NameAndCount(FileName(s.SectionName), s.Chapters);
		}
		private static string FileName(string s)
		{
			s = s.Trim();
			return s
			.Replace("/", "_")
			.Replace("\\", "_")
			.Replace("\"", "'")
			.Replace(":", " -")
			.Replace("?", "")
			.Replace("#", "")
			.Replace("\r\n", " ")
			.Replace("\n", " ")
			.Replace("  ", " ")
			.Replace(" ", "_")
            .Replace(" ", "_")
            .Replace(" ", "_")
            .Replace("__", "_")
            .Replace("__", "_")
            .Replace("__", "_")
            .Replace("__", "_")
			.Replace("=>", "-").ToLower();
		}

		private static string ToHtml_Content(CSection section, CTemplate c, CUser u)
		{
			var p1 = (1 + section.Book.Sections.IndexOf(section));
			var sb = new StringBuilder();
			foreach (var i in section.Chapters)
			{
				var p2 = (1 + section.Chapters.IndexOf(i));

				var id = Math.Abs(i.ChapterNodeGuid.GetHashCode()).ToString();
				c.Reset();
				c.Replace("ChapterId", id);
				c.Replace("ChapterId", id);
				c.Replace("ChapterName", i.ChapterName);
				c.Replace("SectionId", i.ChapterSectionId.ToString());
				c.Replace("Prefix", string.Concat(p1, ".", p2));
				c.Replace("Date", CUtilities.LongDateTime(i.ChapterCreated));
				c.Replace("Rating", i.Rating?.TagName);
                c.Replace("Comments", new CWebClient(30000).DownloadString("http://localhost/facebook/pages/chapters/comments.aspx?chapterId=" + i.ChapterId));

                //var r = i.Node_(u).Root;
                //var f = r.Fields;
                //string s = r.ContentMessageOrName;

                //Content
                var s = i.ChapterText;
				s = HttpUtility.HtmlEncode(s);
				s = s.Replace("\r\n", "\n").Replace("\n\n", "</p><p>").Replace("\n", "<br/>");


				//Photos
				var photos = string.Empty;
				if (i.ChapterPictures.Count > 0) //(r.HasPhotoIds)
				{
					var ids = i.ChapterPictures.Photos.Ids;// r.PhotoIds;
					var usePanel = s.Length > 10000;
					photos = Photos(ids, usePanel);

					if (usePanel || ids.Count <= 2)
					{
						c.Replace("PhotosTop", photos);
						photos = string.Empty;
					}
				}

				c.Replace("Content", s);
				c.Replace("PhotosBottom", photos);
				c.Replace("PhotosTop", string.Empty);

				sb.AppendLine(c.Template);
			}
			return sb.ToString();
		}

		//Links
		private static string ToHtml_Links(CBook b, int sectionId, CTemplate s, CTemplate c, CUser u)
		{
			if (sectionId > 0)
				return string.Empty;

			var sb = new StringBuilder();
			foreach (var i in b.Sections)
			{
				if (sectionId > 0)
					if (i.SectionId != sectionId)
						continue;

				var p1 = (1 + b.Sections.IndexOf(i));

				s.Reset();
				s.Replace("SectionId", i.SectionId.ToString());
				s.Replace("SectionName", i.SectionName);
				s.Replace("Prefix", string.Concat(p1, ". "));
				s.Replace("Chapters", ToHtml_Content(i, c, u));
				s.Replace("ChapterLinks", ToHtml_Links(i, c));
				sb.AppendLine(s.Template);
			}
			return sb.ToString();
		}
		private static string ToHtml_Links(CSection s, CTemplate c)
		{
			var p1 = (1 + s.Book.Sections.IndexOf(s));
			var sb = new StringBuilder();
			var ss = s.Book.Sections;
			foreach (var i in s.Chapters)
			{
				var p2 = (1 + s.Chapters.IndexOf(i));

				var id = Math.Abs(i.ChapterNodeGuid.GetHashCode()).ToString();
				c.Reset();
				c.Replace("ChapterId", id);
				c.Replace("ChapterName", i.ChapterName);			
				c.Replace("SectionId", i.ChapterSectionId.ToString());
				c.Replace("Prefix", string.Concat(p1, ".", p2));
				sb.AppendLine(c.Template);
			}
			return sb.ToString();
		}


		#endregion





		#region Photos
		private static string Photos(List<Guid> ids, bool usePanel)
		{
			if (ids.Count == 0)
				return string.Empty;
			if (ids.Count == 1)
				return PhotoDiv(ids[0], 300);
			if (ids.Count == 2)
				return PhotoPanel(ids, 300, 2);

			if (usePanel)
				return PhotoPanel(ids);
			return PhotoPanelHoriz(ids);
			//return PhotoTbl(ids, 10);
		}
		private static string PhotoPanel(List<Guid> ids, int width = 180, int multiplier = 1)
		{
			StringBuilder sb = new StringBuilder();
			sb.Append("<div style='width:auto").Append("; float:left'>");

			foreach (var i in ids)
				sb.AppendLine(PhotoDivHoriz(i, width, "margin-bottom:5px; margin-right:20px"));

			sb.AppendLine("</div>");
			return sb.ToString().Replace("clear:both", "");
		}

		private static string PhotoPanelHoriz(List<Guid> ids, int height = 150)
		{
			StringBuilder sb = new StringBuilder("<div style='clear:both;display:table'>");

			foreach (var i in ids)
				sb.AppendLine(PhotoDivHoriz(i, height, "margin-bottom:5px; margin-right:20px"));

			sb.AppendLine("</div>");
			return sb.ToString();
		}


		private static string PhotoDiv(Guid id, int width, string style = "", string left = "left")
		{
			string img = PhotoImg(id, width.ToString());

            var ph = CPhotoHash.Cache.GetById(id);
            if (!string.IsNullOrEmpty(ph.PhotoCaptions))
                img = string.Concat(img, "<div style='width:", width, "px; max-height:", width + 50, "px; margin-left:-15px; overflow:auto'><span style='font-size:10px'>", HttpUtility.HtmlEncode(ph.PhotoCaptions).Replace("\r\n", "<br/>"), "</span></div>");

            return string.Concat("<div style='float:", left, "; clear:both; width:", width, "px; ", style, "'>", img, "</div>");
		}
		private static string PhotoDivHoriz(Guid id, int height, string style = "")
        {
            string img = PhotoImg(id, height.ToString()).Replace("width", "height");


            var div_img = string.Concat("<div style='float:left; height:", height, "px; ", style, "'>", img, "</div>");

            var ph = CPhotoHash.Cache.GetById(id);
            if (!string.IsNullOrEmpty(ph.PhotoCaptions))
            {
                var span = string.Concat("<span style='font-size:10px'>", HttpUtility.HtmlEncode(ph.PhotoCaptions), "</span>");
                var div_span = string.Concat("<div style='float:left; max-height:", height, "px; width:", height, "px;overflow:auto'>", span, "</div>");
                div_img += div_span;
            }
            return div_img;
        }
        private static string PhotoImg(Guid id, string width)
		{
			CPhotoHash ph = CPhotoHash.Cache.GetById(id);

			var name = ImageFileName(ph);
			var folder = FolderName(ph);
			var imgPath = "../images/" + folder +  name;

			var url = imgPath.ToLower(); //string.Concat("http://recyclebin.mikeconnellministries.com/photo.aspx?id=", id);
			var img = string.Concat("<img src=\"", url, "\" width=\"", width, "\" />");
			var lnk = string.Concat("<a href=\"", url, "\" target=_blank>", img, "</a>");
			return lnk;
		}
		#endregion


	}

}
